home *** CD-ROM | disk | FTP | other *** search
- /*
- * lfsSegUsage.c --
- *
- * Routines and data structures providing knowledge more segments
- * block usage. This module managers the segment usage array and
- * implements the selection of the next segment to write and to
- * clean. This module should be notified of all block deallocation
- * inorder to make intelligent choices. The module also detects
- * "logwrap" and starts with block cleaner and generates "df"
- * numbers.
- *
- * For each LFS, the module classifies segment into one of three classes:
- * clean, dirty, or full. A segment is clean if it
- * contains no live data. A segment is dirty if it is not clean
- * and has fewer activeBytes than permitable. A segment is full if
- * it is neither clean nor dirty.
- *
- * Copyright 1989 Regents of the University of California
- * Permission to use, copy, modify, and distribute this
- * software and its documentation for any purpose and without
- * fee is hereby granted, provided that the above copyright
- * notice appear in all copies. The University of California
- * makes no representations about the suitability of this
- * software for any purpose. It is provided "as is" without
- * express or implied warranty.
- */
-
- #ifndef lint
- static char rcsid[] = "$Header: /sprite/src/kernel/lfs/RCS/lfsSegUsage.c,v 1.14 91/08/08 17:49:54 mendel Exp $ SPRITE (Berkeley)";
- #endif /* not lint */
-
- #include <lfsInt.h>
- #include <lfsSeg.h>
- #include <lfsStableMemInt.h>
- #include <lfsSegUsageInt.h>
-
- #include <fsdm.h>
-
- int lfsMinCleanThreshold = 5;
-
- /*
- *----------------------------------------------------------------------
- *
- * LfsSegUsageFreeBlocks --
- *
- * Inform the segment usage manager that blocks are no long needed.
- *
- * Results:
- * SUCCESS if the blocks are valid.
- *
- * Side effects:
- * Seg usage map.
- *
- *----------------------------------------------------------------------
- */
-
- ReturnStatus
- LfsSegUsageFreeBlocks(lfsPtr, blockSize, blockArrayLen, blockArrayPtr)
- Lfs *lfsPtr; /* File system of interest. */
- int blockSize; /* Size in bytes of blocks to free. */
- int blockArrayLen; /* Number of elements in blockArrayPtr. */
- LfsDiskAddr *blockArrayPtr; /* Array of disk addresses. */
- {
- int i;
- LfsDiskAddr diskAddress;
-
- for (i = 0; i < blockArrayLen; i++) {
- diskAddress = *blockArrayPtr;
- if (!LfsIsNilDiskAddr(diskAddress)) {
- LfsSetNilDiskAddr(blockArrayPtr);
- LFS_STATS_INC(lfsPtr->stats.segusage.blocksFreed);
- LFS_STATS_ADD(lfsPtr->stats.segusage.bytesFreed, blockSize);
- LfsSetSegUsage(lfsPtr,
- LfsDiskAddrToSegmentNum(lfsPtr, diskAddress), -blockSize);
- }
- blockArrayPtr++;
- }
- return SUCCESS;
- }
-
- /*
- *----------------------------------------------------------------------
- *
- * SegUsageAllocateBytes --
- *
- * Inform the file system for the need to allocate some bytes.
- *
- * Results:
- * SUCCESS if the allocation works, failure otherwise.
- *
- * Side effects:
- *
- *
- *----------------------------------------------------------------------
- */
- ReturnStatus
- LfsSegUsageAllocateBytes(lfsPtr, numBytes)
- Lfs *lfsPtr; /* File system of interest. */
- int numBytes; /* Number of file system bytes needed. */
- {
- LfsSegUsage *usagePtr = &(lfsPtr->usageArray);
- LfsSegUsageCheckPoint *cp = &(usagePtr->checkPoint);
- int blocks;
-
- blocks = LfsBytesToBlocks(lfsPtr, numBytes);
- if (cp->freeBlocks - blocks > usagePtr->params.minFreeBlocks) {
- return SUCCESS;
- }
- return FS_NO_DISK_SPACE;
- }
-
- /*
- *----------------------------------------------------------------------
- *
- * SegUsageFreeBytes --
- *
- * Inform the file system that the previously allocated bytes are
- * nolonger needed or have already been allocated on disk.
- *
- * Results:
- * SUCCESS if the allocation works, failure otherwise.
- *
- * Side effects:
- *
- *
- *----------------------------------------------------------------------
- */
- ReturnStatus
- LfsSegUsageFreeBytes(lfsPtr,numBytes)
- Lfs *lfsPtr; /* File system of interest. */
- int numBytes; /* Number of file system bytes to free. */
- {
- return SUCCESS;
- }
-
- /*
- *----------------------------------------------------------------------
- *
- * LfsCheckRead --
- *
- * Check to see if it is ok to read the specified byte range.
- *
- * Results:
- *
- * Side effects:
- *
- *
- *----------------------------------------------------------------------
- */
- void
- LfsCheckRead(lfsPtr,diskAddress, numBytes)
- Lfs *lfsPtr; /* File system of interest. */
- LfsDiskAddr diskAddress; /* Disk address of read. */
- int numBytes; /* Number of bytes being read. */
- {
- LfsSegUsage *usagePtr = &(lfsPtr->usageArray);
- register LfsSegUsageEntry *s;
- int segNo, segNo2, blocks;
- ReturnStatus status;
- LfsDiskAddr newDiskAddr;
- LfsStableMemEntry smemEntry;
-
- segNo = LfsDiskAddrToSegmentNum(lfsPtr, diskAddress);
- if ((segNo < 0) || (segNo >= usagePtr->params.numberSegments)) {
- panic("LfsOkToRead bad segment number %d\n", segNo);
- return;
- }
- status = LfsStableMemFetch(&(usagePtr->stableMem),segNo,0,&smemEntry);
- if (status != SUCCESS) {
- panic("LfsOkToRead can't fetch usage array block.\n");
- }
- s = (LfsSegUsageEntry *) LfsStableMemEntryAddr(&smemEntry);
-
- if (s->flags & LFS_SEG_USAGE_CLEAN) {
- panic("LfsOkToRead read from clean segment\n");
- LfsStableMemRelease(&(usagePtr->stableMem), &smemEntry, FALSE);
- return;
- }
- LfsStableMemRelease(&(usagePtr->stableMem), &smemEntry, FALSE);
- blocks = LfsBytesToBlocks(lfsPtr, numBytes)-1;
- LfsDiskAddrPlusOffset(diskAddress, blocks, &newDiskAddr);
- segNo2 = LfsDiskAddrToSegmentNum(lfsPtr, newDiskAddr);
- if (segNo2 != segNo) {
- printf("LfsOkToRead read over segment boundary.\n");
- }
-
- }
-
- /*
- *----------------------------------------------------------------------
- *
- * LfsSetSegUsage --
- *
- * Set the usage level of the specified segment.
- *
- * Results:
- * None
- *
- * Side effects:
- * Seg usage array may be modified.
- *
- *----------------------------------------------------------------------
- */
-
- void
- LfsSetSegUsage(lfsPtr, segNumber, activeBytes)
- Lfs *lfsPtr; /* File system of interest. */
- int segNumber; /* Segment number in file system. */
- int activeBytes; /* Usage level Change. */
- {
- LfsSegUsage *usagePtr = &(lfsPtr->usageArray);
- LfsSegUsageCheckPoint *cp = &(usagePtr->checkPoint);
- register LfsSegUsageEntry *s;
- ReturnStatus status;
- LfsStableMemEntry smemEntry;
-
- LFS_STATS_INC(lfsPtr->stats.segusage.usageSet);
- if ((segNumber < 0) || (segNumber >= usagePtr->params.numberSegments)) {
- panic("LfsSetSegUsage bad segment number %d\n", segNumber);
- return;
- }
- if (activeBytes == 0) {
- printf("LfsSetSegUsage: SegNo %d activeBytes %d\n", segNumber,
- activeBytes);
- }
- /*
- * We special case the current segment we are writing to.
- */
- if (segNumber == cp->currentSegment) {
- int oldActiveBytes = cp->curSegActiveBytes;
- cp->curSegActiveBytes += activeBytes;
- if (cp->curSegActiveBytes < 0) {
- printf("LfsSetSegUsage: Warning activeBytes for segment %d is %d\n",
- segNumber, cp->curSegActiveBytes);
- cp->curSegActiveBytes = 0;
- }
- cp->freeBlocks += (LfsBytesToBlocks(lfsPtr, oldActiveBytes) -
- LfsBytesToBlocks(lfsPtr, cp->curSegActiveBytes));
- return;
- }
- status = LfsStableMemFetch(&(usagePtr->stableMem), segNumber,
- LFS_STABLE_MEM_MAY_DIRTY, &smemEntry);
- if (status != SUCCESS) {
- panic("LfsSetSegUsage can't fetch usage array block.\n");
- return;
- }
- s = (LfsSegUsageEntry *) LfsStableMemEntryAddr(&smemEntry);
-
-
- activeBytes = s->activeBytes + activeBytes;
- if (activeBytes < 0) {
- printf("LfsSetSegUsage: Warning activeBytes for segment %d is %d\n",
- segNumber, activeBytes);
- activeBytes = 0;
- }
- cp->freeBlocks += (LfsBytesToBlocks(lfsPtr, s->activeBytes) -
- LfsBytesToBlocks(lfsPtr, activeBytes));
- if (s->flags & LFS_SEG_USAGE_CLEAN) {
- panic("LfsSetSegUsage called on a clean segment (%d)\n", segNumber);
- LfsStableMemRelease(&(usagePtr->stableMem), &smemEntry, FALSE);
- return;
- }
- /*
- * Is it moving onto dirty list?
- */
- if (activeBytes <= cp->dirtyActiveBytes) {
- if (s->flags & LFS_SEG_USAGE_DIRTY) {
- /*
- * All ready on dirty list then do nothing.
- */
- s->activeBytes = activeBytes;
- LfsStableMemRelease(&(usagePtr->stableMem), &smemEntry, TRUE);
- return;
- }
- s->activeBytes = activeBytes;
- s->flags |= LFS_SEG_USAGE_DIRTY;
- cp->numDirty++;
- LfsStableMemRelease(&(usagePtr->stableMem), &smemEntry, TRUE);
- return;
- }
- /*
- * Segment is not clean or dirty just full.
- */
- if (s->flags & LFS_SEG_USAGE_DIRTY) {
- s->flags &= ~LFS_SEG_USAGE_DIRTY;
- cp->numDirty--;
- }
- s->activeBytes = activeBytes;
- LfsStableMemRelease(&(usagePtr->stableMem), &smemEntry, TRUE);
-
- }
-
- /*
- *----------------------------------------------------------------------
- *
- * LfsMarkSegsClean --
- *
- * Mark the specified segments as clean.
- *
- * Results:
- * None
- *
- * Side effects:
- * Seg usage array may be modified.
- *
- *----------------------------------------------------------------------
- */
-
- void
- LfsMarkSegsClean(lfsPtr, numSegs, segs)
- Lfs *lfsPtr; /* File system of interest. */
- int numSegs; /* Number of segments in list. */
- LfsSegList *segs; /* Segments to mark clean. */
- {
- LfsSegUsage *usagePtr = &(lfsPtr->usageArray);
- LfsSegUsageCheckPoint *cp = &(usagePtr->checkPoint);
- register LfsSegUsageEntry *s;
- int i, segNumber, first, previous, flags, nextSeg;
- ReturnStatus status;
- LfsStableMemEntry smemEntry;
-
- /*
- * Build a list of the segment to mark clean.
- */
- first = previous = -1;
- flags = LFS_STABLE_MEM_MAY_DIRTY;
- for (i = 0; i < numSegs; i++) {
- if (segs[i].segNumber == -1) {
- /*
- * Segments get marked with -1 if we can't clean them.
- */
- continue;
- }
- segNumber = segs[i].segNumber;
-
- status = LfsStableMemFetch(&(usagePtr->stableMem), segNumber,
- flags, &smemEntry);
- if (status != SUCCESS) {
- panic("LfsMarkSegClean can't fetch segment %d usage array.",
- segNumber);
- return;
- }
- flags |= LFS_STABLE_MEM_REL_ENTRY;
- s = (LfsSegUsageEntry *) LfsStableMemEntryAddr(&smemEntry);
- if (s->flags & LFS_SEG_USAGE_CLEAN) {
- /*
- * Already clean, skip it.
- */
- continue;
- }
- /*
- * Segment is being marked clean. Remove from dirty list if necessary.
- */
- if (s->flags & LFS_SEG_USAGE_DIRTY) {
- s->flags &= ~LFS_SEG_USAGE_DIRTY;
- cp->numDirty--;
- }
- cp->numClean++;
- s->flags = LFS_SEG_USAGE_CLEAN;
- s->activeBytes = previous;
- LfsStableMemMarkDirty(&smemEntry);
- if (previous == -1) {
- first = segNumber;
- }
- previous = segNumber;
- }
-
- if (previous == -1) {
- /*
- * Nothing to clean.
- */
- return;
- }
-
- /*
- * Insert the new list into the list of already clean
- * segments. We insert this segment as the second element on
- * the list. This requires two Fetchs:
- * 1) Update the head of list segment to point at us.
- * 2) Update us to point at what the head of list use to.
- */
- status = LfsStableMemFetch(&(usagePtr->stableMem), cp->cleanSegList,
- flags, &smemEntry);
- if (status != SUCCESS) {
- panic("LfsMarkSegClean can't fetch usage array.");
- return;
- }
- s = (LfsSegUsageEntry *) LfsStableMemEntryAddr(&smemEntry);
- nextSeg = s->activeBytes;
- s->activeBytes = previous;
- LfsStableMemMarkDirty(&smemEntry);
-
- status = LfsStableMemFetch(&(usagePtr->stableMem), first,
- LFS_STABLE_MEM_MAY_DIRTY|LFS_STABLE_MEM_REL_ENTRY,
- &smemEntry);
- if (status != SUCCESS) {
- panic("LfsMarkSegClean can't fetch usage array.");
- return;
- }
- s = (LfsSegUsageEntry *) LfsStableMemEntryAddr(&smemEntry);
- s->activeBytes = nextSeg;
- LfsStableMemRelease(&(usagePtr->stableMem), &smemEntry, TRUE);
- return;
- }
-
- /*
- *----------------------------------------------------------------------
- *
- * LfsSetDirtyLevel --
- *
- * Set the usage level below which a segment is considered dirty.
- *
- * Results:
- * None
- *
- * Side effects:
- * Seg usage array may be modified.
- *
- *----------------------------------------------------------------------
- */
-
- void
- LfsSetDirtyLevel(lfsPtr, dirtyActiveBytes)
- Lfs *lfsPtr;
- int dirtyActiveBytes; /* New level. */
- {
- LfsSegUsage *usagePtr = &(lfsPtr->usageArray);
- LfsSegUsageCheckPoint *cp = &(usagePtr->checkPoint);
- register LfsSegUsageEntry *s;
- register int segNum;
- ReturnStatus status;
- LfsStableMemEntry smemEntry;
-
-
- cp->dirtyActiveBytes = dirtyActiveBytes;
- for (segNum = 0; segNum < usagePtr->params.numberSegments; segNum++) {
- status = LfsStableMemFetch(&(usagePtr->stableMem), segNum,
- LFS_STABLE_MEM_MAY_DIRTY|
- ((segNum > 0) ? LFS_STABLE_MEM_REL_ENTRY : 0),
- &smemEntry);
-
- if (status != SUCCESS) {
- panic("LfsSetDirtyLevel can't fetch usage array block.\n");
- }
- s = (LfsSegUsageEntry *) LfsStableMemEntryAddr(&smemEntry);
- if (s->activeBytes <= dirtyActiveBytes) {
- if (s->flags & (LFS_SEG_USAGE_DIRTY|LFS_SEG_USAGE_CLEAN)) {
- /*
- * All ready on dirty or clean list then do nothing.
- */
- } else {
- s->flags |= LFS_SEG_USAGE_DIRTY;
- cp->numDirty++;
- LfsStableMemMarkDirty(&smemEntry);
- }
- }
- }
- LfsStableMemRelease(&(usagePtr->stableMem), &smemEntry, FALSE);
-
- }
-
-
- /*
- *----------------------------------------------------------------------
- *
- * Lfs_DomainInfo --
- *
- * Return info about the given domain lfsDomain.
- *
- * Results:
- * SUCCESS
- *
- * Side effects:
- * The domain info struct is filled in.
- *
- *----------------------------------------------------------------------
- */
- ReturnStatus
- Lfs_DomainInfo(domainPtr, domainInfoPtr)
- Fsdm_Domain *domainPtr;
- Fs_DomainInfo *domainInfoPtr;
- {
- Lfs *lfsPtr = LfsFromDomainPtr(domainPtr);
- LfsSegUsage *usagePtr = &(lfsPtr->usageArray);
- LfsSegUsageCheckPoint *cp = &(usagePtr->checkPoint);
- int numSegAvail, numBlocksAvail;
-
- /*
- * Compute the number of segments available for blocks.
- */
- numSegAvail = usagePtr->params.numberSegments -
- usagePtr->params.minNumClean;
-
- domainInfoPtr->maxKbytes = (LfsSegSize(lfsPtr)/1024) * numSegAvail;
-
- /*
- * Compute the number of block available.
- */
- numBlocksAvail = cp->freeBlocks - usagePtr->params.minFreeBlocks;
- if (numBlocksAvail < 0) {
- numBlocksAvail = 0;
- }
-
- domainInfoPtr->freeKbytes = LfsBlocksToBytes(lfsPtr, numBlocksAvail) / 1024;
-
- domainInfoPtr->maxFileDesc = lfsPtr->descMap.params.maxDesc;
- domainInfoPtr->freeFileDesc = lfsPtr->descMap.params.maxDesc -
- lfsPtr->descMap.checkPoint.numAllocDesc;
- domainInfoPtr->blockSize = FS_BLOCK_SIZE;
- domainInfoPtr->optSize = FS_BLOCK_SIZE;
-
-
- return(SUCCESS);
- }
-
-
-
- /*
- *----------------------------------------------------------------------
- *
- * LfsGetLogTail --
- *
- * Get the next available clean blocks to write the log to.
- *
- * Results:
- * SUCCESS if log space was retrieved. FS_NO_DISK_SPACE if log
- * space is not available. FS_WOULD_BLOCK if operation of blocked.
- *
- * Side effects:
- *
- *
- *----------------------------------------------------------------------
- */
-
- ReturnStatus
- LfsGetLogTail(lfsPtr, cantWait, logRangePtr, startBlockPtr)
- Lfs *lfsPtr; /* File system of interest. */
- Boolean cantWait; /* TRUE if we can't wait for a clean seg. */
- LfsSegLogRange *logRangePtr; /* Segments numbers returned. */
- int *startBlockPtr; /* OUT: Starting offset into segment. */
- {
- LfsSegUsage *usagePtr = &(lfsPtr->usageArray);
- LfsSegUsageCheckPoint *cp = &(usagePtr->checkPoint);
- LfsSegUsageEntry *s;
- int segNumber;
- ReturnStatus status;
- LfsStableMemEntry smemEntry;
-
-
- if (!cantWait &&
- (cp->numClean <=
- lfsPtr->usageArray.params.minNumClean + lfsMinCleanThreshold)) {
- LfsSegCleanStart(lfsPtr);
- if (cp->numClean <= lfsPtr->usageArray.params.minNumClean) {
- return FS_WOULD_BLOCK;
- }
- }
- if (cp->currentBlockOffset != -1) {
- /*
- * There is still room in the existing segment. Use it.
- */
- logRangePtr->prevSeg = cp->previousSegment;
- logRangePtr->current = cp->currentSegment;
- logRangePtr->nextSeg = cp->cleanSegList;
- (*startBlockPtr) = cp->currentBlockOffset;
- return SUCCESS;
- }
- /*
- * Need to location a new segment.
- */
- if (cp->numClean == 0) {
- return FS_NO_DISK_SPACE;
- }
- /*
- * Update the active bytes of the current segment the usage array.
- */
- status = LfsStableMemFetch(&(usagePtr->stableMem), cp->currentSegment,
- LFS_STABLE_MEM_MAY_DIRTY, &smemEntry);
- if (status == SUCCESS) {
- s = (LfsSegUsageEntry *) LfsStableMemEntryAddr(&smemEntry);
- s->activeBytes = cp->curSegActiveBytes;
- if (s->activeBytes <= cp->dirtyActiveBytes) {
- s->flags |= LFS_SEG_USAGE_DIRTY;
- cp->numDirty++;
- }
- s->timeOfLastWrite = usagePtr->timeOfLastWrite;
- LfsStableMemMarkDirty(&smemEntry);
- } else {
- panic("LfsGetCleanSeg can't fetch usage array.");
- }
-
- segNumber = cp->cleanSegList;
- status = LfsStableMemFetch(&(usagePtr->stableMem), segNumber,
- (LFS_STABLE_MEM_MAY_DIRTY|
- LFS_STABLE_MEM_REL_ENTRY), &smemEntry);
- if (status != SUCCESS) {
- panic("LfsGetCleanSeg can't fetch usage array.");
- return status;
- }
-
- s = (LfsSegUsageEntry *) LfsStableMemEntryAddr(&smemEntry);
- cp->cleanSegList = s->activeBytes;
-
- logRangePtr->prevSeg = cp->previousSegment = cp->currentSegment;
- logRangePtr->current = cp->currentSegment = segNumber;
- logRangePtr->nextSeg = cp->cleanSegList;
-
- usagePtr->timeOfLastWrite = 0;
- cp->numClean--;
- s->activeBytes = cp->curSegActiveBytes = 0;
- if (cp->numClean <= lfsPtr->usageArray.params.minNumClean) {
- LfsSegCleanStart(lfsPtr);
- }
- s->flags &= ~LFS_SEG_USAGE_CLEAN;
- LfsStableMemRelease(&(usagePtr->stableMem), &smemEntry, TRUE);
- (*startBlockPtr) = 0;
- return SUCCESS;
- }
-
- /*
- *----------------------------------------------------------------------
- *
- * LfsSetLogTail --
- *
- * Set the next available clean blocks to write the log to.
- *
- * Results:
- * None
- *
- * Side effects:
- *
- *
- *----------------------------------------------------------------------
- */
-
- void
- LfsSetLogTail(lfsPtr, logRangePtr, startBlock, activeBytes, timeOfLastWrite)
- Lfs *lfsPtr; /* File system of interest. */
- LfsSegLogRange *logRangePtr; /* Segments numbers returned. */
- int startBlock; /* Starting offset into segment. */
- int activeBytes; /* Number of bytes written. */
- int timeOfLastWrite; /* Youngest block in segment. */
- {
- LfsSegUsage *usagePtr = &(lfsPtr->usageArray);
- LfsSegUsageCheckPoint *cp = &(usagePtr->checkPoint);
-
- cp->currentBlockOffset = startBlock;
- if (usagePtr->timeOfLastWrite < timeOfLastWrite) {
- usagePtr->timeOfLastWrite = timeOfLastWrite;
- }
- if (activeBytes > 0) {
- LfsSetSegUsage(lfsPtr, logRangePtr->current, activeBytes);
- }
- }
-
- /*
- *----------------------------------------------------------------------
- *
- * LfsSegUsageEnoughClean --
- *
- * Check to see if we have enought clean segment to accept this
- * data.
- *
- * Results:
- * TRUE if we do. FALSE if call should wait for some to become
- * available.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
- Boolean
- LfsSegUsageEnoughClean(lfsPtr, dirtyBytes)
- Lfs *lfsPtr;
- int dirtyBytes;
- {
- LfsSegUsage *usagePtr = &(lfsPtr->usageArray);
- LfsSegUsageCheckPoint *cp = &(usagePtr->checkPoint);
- int segsAvailable, cleaningThreshold;
-
-
- segsAvailable = cp->numClean - usagePtr->params.minNumClean;
- cleaningThreshold = segsAvailable - lfsMinCleanThreshold;
- if (cleaningThreshold * LfsSegSize(lfsPtr) < dirtyBytes) {
- LfsSegCleanStart(lfsPtr);
- }
- return ((segsAvailable * LfsSegSize(lfsPtr)) > dirtyBytes);
- }
-
- /*
- *----------------------------------------------------------------------
- *
- * LfsGetSegsToClean --
- *
- * Return a set of segments to clean.
- *
- * Results:
- * Number of segments returned.
- *
- * Side effects:
- *
- *
- *----------------------------------------------------------------------
- */
-
- int
- LfsGetSegsToClean(lfsPtr, maxSegArrayLen, segArrayPtr, minNeededToCleanPtr,
- maxAvailToWritePtr)
- Lfs *lfsPtr; /* File system of interest. */
- int maxSegArrayLen; /* The maximum number of segment to clean to
- * return. */
- LfsSegList *segArrayPtr; /* Array of length maxSegArrayLen to return
- * segments to clean. */
- int *minNeededToCleanPtr; /* OUT: Minimum number of segments
- * that should be cleaned.
- */
- int *maxAvailToWritePtr; /* OUT: Maximum number of segments
- * that should be cleaned. Before
- * marking the segment as clean.
- */
- {
- int numberSegs, segNum, blockSize;
- Boolean fullClean;
- int i, j, currentTime;
- LfsSegUsageEntry *s;
- LfsSegUsage *usagePtr = &(lfsPtr->usageArray);
- ReturnStatus status;
- int flags;
- LfsStableMemEntry smemEntry;
-
- (*minNeededToCleanPtr) = 0;
- (*maxAvailToWritePtr) = 0;
- numberSegs = 0;
- blockSize = LfsBlockSize(lfsPtr);
- /*
- * For each segment.
- */
- currentTime = Fsutil_TimeInSeconds();
- flags = LFS_STABLE_MEM_MAY_DIRTY;
- for (segNum = 0; segNum < usagePtr->params.numberSegments; segNum++) {
- /*
- * Execpt the one currently being written.
- */
- if (usagePtr->checkPoint.currentSegment == segNum) {
- continue;
- }
- status = LfsStableMemFetch(&(usagePtr->stableMem), segNum, flags,
- &smemEntry);
- if (status != SUCCESS) {
- panic("LfsSetDirtyLevel can't fetch usage array block.\n");
- return status;
- }
- flags |= LFS_STABLE_MEM_REL_ENTRY;
- s = (LfsSegUsageEntry *)LfsStableMemEntryAddr(&smemEntry);
- /*
- * Find the proper position in the list for this segment.
- */
- /*
- * Patch to fixed up bad activeBytes.
- */
- if (!(s->flags & (LFS_SEG_USAGE_CLEAN|LFS_SEG_USAGE_DIRTY)) &&
- (s->activeBytes <= usagePtr->checkPoint.dirtyActiveBytes)) {
- s->flags |= LFS_SEG_USAGE_DIRTY;
- usagePtr->checkPoint.numDirty++;
- }
- if (s->flags & LFS_SEG_USAGE_DIRTY) {
- int age;
- unsigned int blocks, priority;
- /*
- * Besure the age in minutes is not totally bogus because of
- * startup settings or running the system with a bogus time.
- */
- age = (currentTime - s->timeOfLastWrite)/60;
- if (age > 60*24*365*2) {
- /*
- * If the age is greater that 2 years set it to 2 years.
- */
- age = 60*24*365*2;
- } else if (age <= 0) {
- /*
- * If the age is less or equal to zero set it to 1 minute.
- */
- age = 1;
- }
- /*
- * To do the priority caluation without using floating
- * point we scale the byte values into block values
- * and scale the age into minutes.
- */
- if (s->activeBytes != 0) {
- blocks = LfsBytesToBlocks(lfsPtr, s->activeBytes);
- if (s->activeBytes < 0) {
- blocks = 0;
- }
- priority = ((LfsSegSizeInBlocks(lfsPtr) - blocks) * age) /
- (LfsSegSizeInBlocks(lfsPtr) + blocks);
- } else {
- /*
- * Give zero size segments highest priority.
- */
- priority = 0x7fffffff;
- }
- /*
- * Find the last element in the list with a priority
- * greater the the current segments.
- */
- for (i = numberSegs-1; i >= 0; i--) {
- if (segArrayPtr[i].priority >= priority) {
- break;
- }
- }
- /*
- * Extend the array if it is not full already.
- * Insert new seg at specified position by moving all others down.
- * Don't do insert if position is after the end of the array.
- */
- if (numberSegs < maxSegArrayLen) {
- numberSegs++;
- }
-
- if (i < numberSegs-1) {
- for (j = numberSegs-2; j > i; j--) {
- segArrayPtr[j+1] = segArrayPtr[j];
- }
- segArrayPtr[i+1].segNumber = segNum;
- segArrayPtr[i+1].activeBytes = s->activeBytes;
- segArrayPtr[i+1].priority = priority;
- }
- }
- }
- LfsStableMemRelease(&(usagePtr->stableMem), &smemEntry, FALSE);
- fullClean = ((lfsPtr->controlFlags & LFS_CONTROL_CLEANALL) != 0);
- /*
- * Set the minimum number to get us above the numSegsToClean
- * threashold.
- */
- (*minNeededToCleanPtr) = (usagePtr->params.minNumClean +
- usagePtr->params.numSegsToClean+1) -
- usagePtr->checkPoint.numClean;
- if ((*minNeededToCleanPtr) < 0) {
- (*minNeededToCleanPtr) = 0;
- }
- if (fullClean) {
- (*minNeededToCleanPtr) = numberSegs;
- }
- /*
- * Set the max number to write to use half the minimum number or
- * all but the last 10 - whichever is less.
- */
- (*maxAvailToWritePtr) = usagePtr->params.minNumClean / 2;
- if ((*maxAvailToWritePtr) >= usagePtr->checkPoint.numClean-10) {
- (*maxAvailToWritePtr) = usagePtr->checkPoint.numClean-10;
- }
- return numberSegs;
- }
-
-
- /*
- *----------------------------------------------------------------------
- *
- * LfsSegUsageCheckpointUpdate --
- *
- * This routine is used to update fields of the seg usage
- * checkpoint that change when the checkpoint itself is
- * written to the log.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
- void
- LfsSegUsageCheckpointUpdate(lfsPtr, checkPointPtr, size)
- Lfs *lfsPtr; /* File system being checkpointed. */
- char *checkPointPtr; /* Checkpoint region for SegUsage. */
- int size; /* Size of checkpoint region. */
- {
- LfsSegUsage *usagePtr = &(lfsPtr->usageArray);
-
- if (size < sizeof(LfsSegUsageCheckPoint)) {
- panic("LfsSegUsageCheckpointUpdate bad checkpoint size.\n");
- }
- (*(LfsSegUsageCheckPoint *) checkPointPtr) = usagePtr->checkPoint;
- return;
- }
-
-
- extern ReturnStatus LfsSegUsageAttach _ARGS_((Lfs *lfsPtr,
- int checkPointSize, char *checkPointPtr));
- extern Boolean LfsSegUsageCheckpoint _ARGS_((LfsSeg *segPtr, int flags,
- char *checkPointPtr, int *checkPointSizePtr,
- ClientData *clientDataPtr));
- extern void LfsSegUsageWriteDone _ARGS_((LfsSeg *segPtr, int flags,
- ClientData *clientDataPtr));
- extern Boolean LfsSegUsageClean _ARGS_((LfsSeg *segPtr, int *sizePtr,
- int *numCacheBlocksPtr, ClientData *clientDataPtr));
- extern Boolean LfsSegUsageLayout _ARGS_((LfsSeg *segPtr, int flags,
- ClientData *clientDataPtr));
-
- extern ReturnStatus LfsSegUsageDetach _ARGS_((Lfs *lfsPtr));
-
- static LfsSegIoInterface segUsageIoInterface =
- { LfsSegUsageAttach, LfsSegUsageLayout, LfsSegUsageClean,
- LfsSegUsageCheckpoint, LfsSegUsageWriteDone, LfsSegUsageDetach, 0};
-
-
- /*
- *----------------------------------------------------------------------
- *
- * LfsSegUsageInit --
- *
- * Initialize the segment usage array data structures.
- *
- * Results:
- * None
- *
- * Side effects:
- *
- *----------------------------------------------------------------------
- */
-
- void
- LfsSegUsageInit()
- {
- LfsSegIoRegister(LFS_SEG_USAGE_MOD,&segUsageIoInterface);
- }
-
-
- /*
- *----------------------------------------------------------------------
- *
- * SegUsageAttach --
- *
- * Attach routine for the seg usage map. Creates and initializes the
- * map for this file system.
- *
- * Results:
- * SUCCESS if attaching is going ok.
- *
- * Side effects:
- * Many
- *
- *----------------------------------------------------------------------
- */
-
- ReturnStatus
- LfsSegUsageAttach(lfsPtr, checkPointSize, checkPointPtr)
- Lfs *lfsPtr; /* File system for attach. */
- int checkPointSize; /* Size of checkpoint data. */
- char *checkPointPtr; /* Data from last checkpoint before shutdown. */
- {
- LfsSegUsage *usagePtr = &(lfsPtr->usageArray);
- LfsSegUsageCheckPoint *cp = (LfsSegUsageCheckPoint *) checkPointPtr;
- ReturnStatus status;
-
- /*
- * Allocate and fill in memory data structure for descriptor map.
- */
- usagePtr->params = lfsPtr->superBlock.usageArray;
- usagePtr->checkPoint = *cp;
- usagePtr->timeOfLastWrite = Fsutil_TimeInSeconds();
- /*
- * Load the stableMem and buffer using the LfsStableMem routines.
- */
- status = LfsStableMemLoad(lfsPtr, &(usagePtr->params.stableMem),
- checkPointSize - sizeof(LfsSegUsageCheckPoint),
- checkPointPtr + sizeof(LfsSegUsageCheckPoint),
- &(usagePtr->stableMem));
- if (status != SUCCESS) {
- LfsError(lfsPtr, status,"Can't loading descriptor map stableMem\n");
- return status;
- }
- printf("LfsSegUsageAttach - logEnd <%d,%d>, numClean %d numDirty %d numFull %d\n",
- cp->currentSegment, cp->currentBlockOffset,
- cp->numClean, cp->numDirty,
- usagePtr->params.numberSegments - cp->numClean - cp->numDirty);
- return status;
- }
-
- /*
- *----------------------------------------------------------------------
- *
- * SegUsageDetach --
- *
- * Detach routine for the seg usage array. Destory the
- * array for this file system.
- *
- * Results:
- * SUCCESS if dettach is going ok.
- *
- * Side effects:
- * Many
- *
- *----------------------------------------------------------------------
- */
-
- ReturnStatus
- LfsSegUsageDetach(lfsPtr)
- Lfs *lfsPtr; /* File system for attach. */
- {
- LfsSegUsage *usagePtr = &(lfsPtr->usageArray);
-
- return LfsStableMemDestory(lfsPtr, &(usagePtr->stableMem));
- }
-
- /*
- *----------------------------------------------------------------------
- *
- * SegUsageCheckpoint --
- *
- * Routine to handle checkpointing of the descriptor map data.
- *
- * Results:
- * TRUE if more data needs to be written, FALSE if this module is
- * checkpointed.
- *
- * Side effects:
- * Many
- *
- *----------------------------------------------------------------------
- */
-
- Boolean
- LfsSegUsageCheckpoint(segPtr, flags,checkPointPtr, checkPointSizePtr,
- clientDataPtr)
- LfsSeg *segPtr; /* Segment containing data for checkpoint. */
- char *checkPointPtr; /* Buffer to write checkpoint data. */
- int flags; /* Flags. */
- int *checkPointSizePtr; /* Bytes added to the checkpoint area.*/
- ClientData *clientDataPtr;
- {
- LfsSegUsage *usagePtr = &(segPtr->lfsPtr->usageArray);
- LfsSegUsageCheckPoint *cp = (LfsSegUsageCheckPoint *) checkPointPtr;
- int size;
- Boolean full;
-
- *cp = usagePtr->checkPoint;
- size = sizeof(LfsSegUsageCheckPoint);
-
- full = LfsStableMemCheckpoint(segPtr, checkPointPtr + size, flags,
- checkPointSizePtr, clientDataPtr,
- &(usagePtr->stableMem));
- if (!full) {
- *checkPointSizePtr = (*checkPointSizePtr) + size;
- }
- return full;
-
- }
-
- /*
- *----------------------------------------------------------------------
- *
- * SegUsageWriteDone --
- *
- * Routine to handle finishing of a checkpoint.
- *
- * Results:
- * None
- *
- * Side effects:
- * Many
- *
- *----------------------------------------------------------------------
- */
-
- void
- LfsSegUsageWriteDone(segPtr, flags, clientDataPtr)
- LfsSeg *segPtr; /* Segment containing data for checkpoint. */
- int flags; /* Flags for checkpoint */
- ClientData *clientDataPtr;
- {
- LfsSegUsage *usagePtr = &(segPtr->lfsPtr->usageArray);
-
- LFS_STATS_ADD(segPtr->lfsPtr->stats.segusage.blocksWritten,
- (LfsSegSummaryBytesLeft(segPtr) / sizeof(int)));
- LfsStableMemWriteDone(segPtr, flags, clientDataPtr,
- &(usagePtr->stableMem));
- return;
-
- }
-
-
- /*
- *----------------------------------------------------------------------
- *
- * LfsSegUsageClean --
- *
- * Routine to handle cleaning of descriptor map data.
- *
- * Results:
- * TRUE if more data needs to be written, FALSE if this module is
- * happy for the time being.
- *
- * Side effects:
- *
- *
- *----------------------------------------------------------------------
- */
-
- Boolean
- LfsSegUsageClean(segPtr, sizePtr, numCacheBlocksPtr, clientDataPtr)
- LfsSeg *segPtr; /* Segment containing data to clean. */
- int *sizePtr; /* Size of cleaning. */
- int *numCacheBlocksPtr;
- ClientData *clientDataPtr;
- {
- LfsSegUsage *usagePtr = &(segPtr->lfsPtr->usageArray);
- Boolean full;
-
- full = LfsStableMemClean(segPtr, sizePtr, numCacheBlocksPtr, clientDataPtr,
- &(usagePtr->stableMem));
-
- LFS_STATS_ADD(segPtr->lfsPtr->stats.segusage.blocksCleaned,
- *sizePtr/usagePtr->stableMem.params.blockSize);
- return full;
-
- }
-
-
-
- /*
- *----------------------------------------------------------------------
- *
- * LfsSegUsageLayout --
- *
- * Routine to handle layingout of segUsage data.
- *
- * Results:
- * TRUE if more data needs to be written, FALSE if this module is
- * happy for the time being.
- *
- * Side effects:
- *
- *
- *----------------------------------------------------------------------
- */
-
- Boolean
- LfsSegUsageLayout(segPtr, flags, clientDataPtr)
- LfsSeg *segPtr; /* Segment containing data to clean. */
- int flags; /* Layout flags. */
- ClientData *clientDataPtr;
- {
- LfsSegUsage *usagePtr = &(segPtr->lfsPtr->usageArray);
-
- if ((flags & LFS_CLEANING_LAYOUT) != 0) {
- return FALSE;
- }
- return LfsStableMemLayout(segPtr, flags,
- clientDataPtr, &(usagePtr->stableMem));
- }
-
-